using System;
using System.Collections.Generic;
using System.Linq;

namespace MT5Trade.Models
{
    /// <summary>
    /// Beta系数计算器
    /// 计算资产相对于市场基准的系统性风险
    /// </summary>
    public class BetaCalculator
    {
        #region 常量定义

        // 计算参数
        public const int DEFAULT_PERIOD = 252;              // 默认计算周期（1年）
        public const int MIN_DATA_POINTS = 20;             // 最少数据点
        public const double CONFIDENCE_LEVEL = 0.95;       // 置信水平
        
        // Beta分类阈值
        public const double HIGH_BETA_THRESHOLD = 1.5;     // 高Beta阈值
        public const double LOW_BETA_THRESHOLD = 0.5;      // 低Beta阈值
        public const double DEFENSIVE_BETA = 0.8;          // 防御型Beta
        public const double AGGRESSIVE_BETA = 1.2;         // 进取型Beta

        #endregion

        #region 私有字段

        private readonly Dictionary<string, List<double>> _priceHistory;
        private readonly Dictionary<string, BetaResult> _betaCache;
        private DateTime _lastCalculationTime;

        #endregion

        #region 构造函数

        /// <summary>
        /// 初始化Beta计算器
        /// </summary>
        public BetaCalculator()
        {
            _priceHistory = new Dictionary<string, List<double>>();
            _betaCache = new Dictionary<string, BetaResult>();
            _lastCalculationTime = DateTime.MinValue;
        }

        #endregion

        #region 核心计算方法

        /// <summary>
        /// 计算Beta系数
        /// </summary>
        /// <param name="assetPrices">资产价格序列</param>
        /// <param name="marketPrices">市场基准价格序列</param>
        /// <param name="period">计算周期</param>
        /// <returns>Beta计算结果</returns>
        public BetaResult Calculate(double[] assetPrices, double[] marketPrices, int period = DEFAULT_PERIOD)
        {
            // 参数验证
            if (assetPrices == null || marketPrices == null)
                throw new ArgumentNullException("价格序列不能为空");
            
            if (assetPrices.Length != marketPrices.Length)
                throw new ArgumentException("资产价格和市场价格序列长度必须相同");
            
            if (assetPrices.Length < MIN_DATA_POINTS)
                throw new ArgumentException($"数据点不足，至少需要{MIN_DATA_POINTS}个数据点");

            // 限制计算周期
            int actualPeriod = Math.Min(period, assetPrices.Length);
            
            // 取最近的数据
            var assetData = assetPrices.TakeLast(actualPeriod).ToArray();
            var marketData = marketPrices.TakeLast(actualPeriod).ToArray();
            
            // 计算收益率
            var assetReturns = CalculateReturns(assetData);
            var marketReturns = CalculateReturns(marketData);
            
            // 计算Beta
            double covariance = CalculateCovariance(assetReturns, marketReturns);
            double marketVariance = CalculateVariance(marketReturns);
            
            if (Math.Abs(marketVariance) < 1e-10)
            {
                throw new InvalidOperationException("市场方差为零，无法计算Beta");
            }
            
            double beta = covariance / marketVariance;
            
            // 计算其他统计指标
            double correlation = CalculateCorrelation(assetReturns, marketReturns);
            double r2 = correlation * correlation; // 决定系数
            double alpha = CalculateAlpha(assetReturns, marketReturns, beta);
            double trackingError = CalculateTrackingError(assetReturns, marketReturns, beta);
            
            // 计算Beta的标准误差
            double standardError = CalculateBetaStandardError(assetReturns, marketReturns, beta);
            
            // 构建结果
            var result = new BetaResult
            {
                Beta = beta,
                Alpha = alpha,
                Correlation = correlation,
                RSquared = r2,
                TrackingError = trackingError,
                StandardError = standardError,
                DataPoints = assetReturns.Length,
                Period = actualPeriod,
                CalculationTime = DateTime.UtcNow,
                
                // Beta分类
                BetaClassification = ClassifyBeta(beta),
                
                // 置信区间
                ConfidenceInterval = CalculateConfidenceInterval(beta, standardError),
                
                // 统计显著性
                IsStatisticallySignificant = Math.Abs(beta / standardError) > 2.0
            };
            
            // 缓存结果
            string cacheKey = $"{assetData.GetHashCode()}_{marketData.GetHashCode()}";
            _betaCache[cacheKey] = result;
            _lastCalculationTime = DateTime.UtcNow;
            
            return result;
        }

        /// <summary>
        /// 计算收益率序列
        /// </summary>
        private double[] CalculateReturns(double[] prices)
        {
            if (prices.Length < 2)
                return new double[0];
            
            var returns = new double[prices.Length - 1];
            for (int i = 1; i < prices.Length; i++)
            {
                if (prices[i - 1] > 0)
                {
                    returns[i - 1] = (prices[i] - prices[i - 1]) / prices[i - 1];
                }
                else
                {
                    returns[i - 1] = 0;
                }
            }
            
            return returns;
        }

        /// <summary>
        /// 计算协方差
        /// </summary>
        public double CalculateCovariance(double[] x, double[] y)
        {
            if (x.Length != y.Length || x.Length == 0)
                return 0;
            
            double meanX = x.Average();
            double meanY = y.Average();
            
            double covariance = 0;
            for (int i = 0; i < x.Length; i++)
            {
                covariance += (x[i] - meanX) * (y[i] - meanY);
            }
            
            return covariance / (x.Length - 1);
        }

        /// <summary>
        /// 计算方差
        /// </summary>
        public double CalculateVariance(double[] values)
        {
            if (values.Length < 2)
                return 0;
            
            double mean = values.Average();
            double variance = 0;
            
            foreach (var value in values)
            {
                variance += Math.Pow(value - mean, 2);
            }
            
            return variance / (values.Length - 1);
        }

        /// <summary>
        /// 计算相关系数
        /// </summary>
        private double CalculateCorrelation(double[] x, double[] y)
        {
            double covariance = CalculateCovariance(x, y);
            double stdX = Math.Sqrt(CalculateVariance(x));
            double stdY = Math.Sqrt(CalculateVariance(y));
            
            if (stdX < 1e-10 || stdY < 1e-10)
                return 0;
            
            return covariance / (stdX * stdY);
        }

        /// <summary>
        /// 计算Alpha（超额收益）
        /// </summary>
        private double CalculateAlpha(double[] assetReturns, double[] marketReturns, double beta)
        {
            double assetMean = assetReturns.Average();
            double marketMean = marketReturns.Average();
            
            // Jensen's Alpha: α = R_a - (R_f + β * (R_m - R_f))
            // 简化版本（假设无风险利率为0）: α = R_a - β * R_m
            return assetMean - beta * marketMean;
        }

        /// <summary>
        /// 计算跟踪误差
        /// </summary>
        private double CalculateTrackingError(double[] assetReturns, double[] marketReturns, double beta)
        {
            var trackingDifferences = new double[assetReturns.Length];
            
            for (int i = 0; i < assetReturns.Length; i++)
            {
                // 预期收益 = beta * 市场收益
                double expectedReturn = beta * marketReturns[i];
                trackingDifferences[i] = assetReturns[i] - expectedReturn;
            }
            
            return Math.Sqrt(CalculateVariance(trackingDifferences));
        }

        /// <summary>
        /// 计算Beta的标准误差
        /// </summary>
        private double CalculateBetaStandardError(double[] assetReturns, double[] marketReturns, double beta)
        {
            int n = assetReturns.Length;
            if (n < 3)
                return double.NaN;
            
            // 计算残差
            var residuals = new double[n];
            for (int i = 0; i < n; i++)
            {
                residuals[i] = assetReturns[i] - beta * marketReturns[i];
            }
            
            // 残差方差
            double residualVariance = CalculateVariance(residuals);
            
            // 市场收益方差
            double marketVariance = CalculateVariance(marketReturns);
            
            // Beta的标准误差
            double standardError = Math.Sqrt(residualVariance / ((n - 2) * marketVariance * n));
            
            return standardError;
        }

        /// <summary>
        /// 计算置信区间
        /// </summary>
        private (double Lower, double Upper) CalculateConfidenceInterval(double beta, double standardError)
        {
            // 95%置信区间，使用t分布的近似值1.96
            double marginOfError = 1.96 * standardError;
            return (beta - marginOfError, beta + marginOfError);
        }

        /// <summary>
        /// Beta分类
        /// </summary>
        private BetaClassification ClassifyBeta(double beta)
        {
            if (beta < 0)
                return BetaClassification.Negative;
            else if (beta < LOW_BETA_THRESHOLD)
                return BetaClassification.VeryLow;
            else if (beta < DEFENSIVE_BETA)
                return BetaClassification.Low;
            else if (beta < 1.0)
                return BetaClassification.Defensive;
            else if (beta == 1.0)
                return BetaClassification.Neutral;
            else if (beta < AGGRESSIVE_BETA)
                return BetaClassification.Moderate;
            else if (beta < HIGH_BETA_THRESHOLD)
                return BetaClassification.Aggressive;
            else
                return BetaClassification.VeryHigh;
        }

        #endregion

        #region 高级功能

        /// <summary>
        /// 计算滚动Beta
        /// </summary>
        public List<BetaPoint> CalculateRollingBeta(
            double[] assetPrices, 
            double[] marketPrices, 
            int windowSize = 60,
            int stepSize = 1)
        {
            var rollingBetas = new List<BetaPoint>();
            
            for (int i = windowSize; i <= assetPrices.Length; i += stepSize)
            {
                var assetWindow = assetPrices.Skip(i - windowSize).Take(windowSize).ToArray();
                var marketWindow = marketPrices.Skip(i - windowSize).Take(windowSize).ToArray();
                
                try
                {
                    var result = Calculate(assetWindow, marketWindow, windowSize);
                    rollingBetas.Add(new BetaPoint
                    {
                        Index = i - 1,
                        Beta = result.Beta,
                        Timestamp = DateTime.UtcNow.AddDays(i - assetPrices.Length)
                    });
                }
                catch
                {
                    // 忽略计算错误，继续
                }
            }
            
            return rollingBetas;
        }

        /// <summary>
        /// 计算调整后的Beta（收缩估计）
        /// </summary>
        public double CalculateAdjustedBeta(double rawBeta, double shrinkageFactor = 0.33)
        {
            // Blume调整: β_adjusted = shrinkageFactor * 1.0 + (1 - shrinkageFactor) * β_raw
            // 将Beta向1.0收缩，减少估计误差
            return shrinkageFactor * 1.0 + (1 - shrinkageFactor) * rawBeta;
        }

        /// <summary>
        /// 预测未来Beta（基于历史趋势）
        /// </summary>
        public double PredictFutureBeta(List<BetaPoint> historicalBetas, int periodsAhead = 1)
        {
            if (historicalBetas == null || historicalBetas.Count < 2)
                return 1.0; // 返回中性Beta
            
            // 使用简单线性回归预测
            int n = historicalBetas.Count;
            double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
            
            for (int i = 0; i < n; i++)
            {
                sumX += i;
                sumY += historicalBetas[i].Beta;
                sumXY += i * historicalBetas[i].Beta;
                sumX2 += i * i;
            }
            
            double slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
            double intercept = (sumY - slope * sumX) / n;
            
            // 预测
            double predictedBeta = intercept + slope * (n + periodsAhead - 1);
            
            // 限制预测范围
            return Math.Max(-2.0, Math.Min(3.0, predictedBeta));
        }

        #endregion
    }

    #region 数据结构定义

    /// <summary>
    /// Beta计算结果
    /// </summary>
    public class BetaResult
    {
        public double Beta { get; set; }
        public double Alpha { get; set; }
        public double Correlation { get; set; }
        public double RSquared { get; set; }
        public double TrackingError { get; set; }
        public double StandardError { get; set; }
        public int DataPoints { get; set; }
        public int Period { get; set; }
        public DateTime CalculationTime { get; set; }
        public BetaClassification BetaClassification { get; set; }
        public (double Lower, double Upper) ConfidenceInterval { get; set; }
        public bool IsStatisticallySignificant { get; set; }

        // 兼容性属性
        public double Value => Beta;

        public override string ToString()
        {
            return $"Beta: {Beta:F3} ({BetaClassification}), " +
                   $"Alpha: {Alpha:F4}, R²: {RSquared:F3}, " +
                   $"CI: [{ConfidenceInterval.Lower:F3}, {ConfidenceInterval.Upper:F3}]";
        }
    }

    /// <summary>
    /// Beta分类
    /// </summary>
    public enum BetaClassification
    {
        Negative,     // β < 0，负相关
        VeryLow,      // 0 ≤ β < 0.5，极低
        Low,          // 0.5 ≤ β < 0.8，低
        Defensive,    // 0.8 ≤ β < 1.0，防御型
        Neutral,      // β = 1.0，中性
        Moderate,     // 1.0 < β < 1.2，适度
        Aggressive,   // 1.2 ≤ β < 1.5，进取型
        VeryHigh      // β ≥ 1.5，极高
    }

    /// <summary>
    /// Beta时间点
    /// </summary>
    public class BetaPoint
    {
        public int Index { get; set; }
        public double Beta { get; set; }
        public DateTime Timestamp { get; set; }
    }

    #endregion
}